home *** CD-ROM | disk | FTP | other *** search
/ Skunkware 98 / Skunkware 98.iso / osr5 / sco / scripts / chr < prev    next >
Encoding:
Korn shell script  |  1997-08-26  |  5.7 KB  |  191 lines

  1. #!/bin/ksh
  2. # chr: convert decimal numbers to characters
  3. # @(#) chr.ksh 1.1 97/06/23
  4. # 90/07/07 john h. dubois iii (john@armory.com)
  5. # 91/02/25 added comments
  6. # 92/02/16 added -h option for help
  7. # 92/09/14 Read input if no args given
  8. # 94/04/23 Added all options, multibyte conversions,
  9. #          and conversion of C constant & ksh style integers.
  10. # 95/08/02 Added e option.
  11.  
  12. name=${0##*/}
  13. Usage="Usage: $name [-[bl]<wordsize>] [-o<byte-order>] n [ n ... ]"
  14. typeset -i WordSize=1 i
  15. Debug=false
  16. PrintEsc=
  17. set -A ByteOrder 1
  18.  
  19. while getopts ehb:l:o:x opt; do
  20.     case $opt in
  21.     h)
  22.     print \
  23. "$name: convert integers to byte values.
  24. $Usage
  25. For each integer value n, one or more characters (bytes) with the value of n
  26. are output.  Integers may be given in C contant style (decimal, 0<octal>,
  27. 0x<hex>) or ksh style (base#value).  The values given must be less than or
  28. equal to the largest value that can be encoded in the wordsize, which by
  29. default is 1 byte, giving a maximum value of 255.  If no numbers are given on
  30. the command line, chr reads its input for numbers.
  31. Options:
  32. -e: Instead of printing the bytes directly, print a string argument that could
  33.     be passed to \"echo\" to cause it to print the bytes.  The string will
  34.     contain only non-whitespace printing characters; octal escape codes
  35.     (recognized by echo) will be used for other characters, and for certain
  36.     characters that are liable to cause a problem if used directly in an echo
  37.     statement: single and double quotes, backslashes, dollar signs, and
  38.     hyphens.  A single string will be printed for all of the bytes, with a
  39.     newline at the end.
  40. -b<wordsize>, -l<wordsize>: Set the byte order to big-endian (high-end bytes
  41.     of each value emitted first) or little-endian (low-end bytes first), with
  42.     a word size of <wordsize> bytes.  The default is a word size of 1 byte,
  43.     for which endianness is meaningless.  <wordsize> can be set up to 4, but
  44.     due to limitations of ksh arithmetic, only values up to 2^31-1 (2147483647)
  45.     can be given.
  46. -o<byte-order>: Specify a specific byte order.  Byte order is given as a
  47.     comma-separated series of integers from 1 to n.  n (the highest valued
  48.     integer given) sets the word size. Bytes of each word are emitted in the
  49.     given order.  1 refers to the low-end byte, n to the high-end byte.
  50.     Not all bytes need to be emitted.
  51. -h: Print this help."
  52.     exit 0
  53.     ;;
  54.     b)
  55.     WordSize=$OPTARG || exit 1
  56.     i=0
  57.     while [ i -lt WordSize ]; do
  58.         let ByteOrder[i]=WordSize-i
  59.         let i+=1
  60.     done
  61.     ;;
  62.     e)
  63.     PrintEsc=true
  64.     ;;
  65.     l)
  66.     WordSize=$OPTARG || exit 1
  67.     i=0
  68.     while [ i -lt WordSize ]; do
  69.         let ByteOrder[i]=i+1
  70.         let i+=1
  71.     done
  72.     ;;
  73.     o)
  74.     OIFS=$IFS
  75.     IFS=,
  76.     set -A ByteOrder $OPTARG
  77.     IFS=$OIFS
  78.     for i in "${ByteOrder[@]}"; do
  79.         [ i -gt WordSize ] && WordSize=i
  80.     done
  81.     ;;
  82.     x)
  83.     Debug=true
  84.     ;;
  85.     +?)
  86.     print -u2 "$name: options should not be preceded by a '+'."
  87.     exit 1
  88.     ;;
  89.     ?)
  90.         print -r -u2 "Use -h for help."
  91.         exit 1
  92.         ;;
  93.     esac
  94. done
  95.  
  96. # remove args that were options
  97. let OPTIND=OPTIND-1
  98. shift $OPTIND
  99.  
  100. # Usage: PrintChrs value1 ...
  101. # Print the characters whose ASCII value are value1 ....
  102. # Globals used:
  103. # ByteOrder[]: Tells the order that bytes should be emitted in.
  104. # Index 0 of ByteOrder[] tells which byte should be emitted first, etc.
  105. # Bytes are numbered 1..n for low to high byte.
  106. # PrintEsc: Non-null if instead of printing the actual characters, the
  107. # string to pass to echo to print the characters should be printed.
  108. # No newline is printed at the end whether or not PrintEsc is used.
  109. # This string will contain only non-whitespace printing characters.
  110. function PrintChrs {
  111.     # Result[1..n] stores low..high bytes of value
  112.     typeset -i ByteNum word Result
  113.     # Print value in octal for use in echo sequence
  114.     typeset -i8 value
  115.  
  116.     # Build up the entire string before echoing it so that the echo
  117.     # command can be echoed instead if we want
  118.     cbase "$@" || exit 1
  119.     for word in ${cbase_ret[@]}; do
  120.     if [ word -gt MaxVal ]; then
  121.         print -u2 "Value too large: $word"
  122.         exit 1
  123.     fi
  124.     ByteNum=1
  125.     while [ ByteNum -le WordSize ]; do
  126.         let Result[ByteNum]=word%256
  127.         word=word/256
  128.         let ByteNum+=1
  129.     done
  130.     # Print selected bytes in specified order.
  131.     for ByteNum in "${ByteOrder[@]}"; do
  132.         value=${Result[ByteNum]}
  133.         # strip leading #8 from printed value so it will be in the
  134.         # form expected by echo
  135.         EscSeq="\0${value#8#}"
  136.         # Even if PrintEsc is on, print byte values directly if they are
  137.         # printable & not whitespace or other problem chars
  138.         [[ -z "$PrintEsc" || ( value -gt 32 && value -lt 127 &&
  139.         value -ne 39 && value -ne 34 && value -ne 92 && value -ne 45 &&
  140.         value -ne 36 ) ]] &&
  141.         print -n -- "$EscSeq" || print -nr -- "$EscSeq"
  142.     done
  143.     done
  144. }
  145.  
  146. # Usage: cbase c-contant ...
  147. # convert hex (0xnnn and 0Xnnn), octal (0nnn), and decimal C constants, and
  148. # ksh-style (base#value) contants, to integers & store in global
  149. # cbase_ret[0..n-1]
  150. # 1 is returned on error, 0 on success
  151. typeset -i10 cbase_ret
  152. cbase() {
  153.     typeset -i10 d i=0
  154.     unset cbase_ret[*]
  155.     while [ $# -gt 0 ]; do
  156.     case $1 in
  157.         0[xX]*([0-9a-fA-F]) ) d=16#${1#0[xX]};;    # hex
  158.         0*([0-7]) ) d=8#$1;;            # octal
  159.         [1-9]*([0-9]) ) d=$1;;            # decimal
  160.         +([0-9])#+([0-9]) ) d=$1;;            # ksh
  161.         *) print -u2 "Bad number: $1"; return 1;;
  162.     esac
  163.     cbase_ret[i]=$d
  164.     let i+=1
  165.     shift
  166.     done
  167.     return 0
  168. }
  169.  
  170. typeset -i MaxVal
  171. case $WordSize in
  172. 1)  MaxVal=255;;
  173. 2)  MaxVal=65536;;
  174. 3)  MaxVal=16777215;;
  175. 4)  MaxVal=2147483647;;
  176. *)  print -u2 "$Name: bad wordsize: $WordSize."
  177.     exit 1;;
  178. esac
  179.  
  180. $Debug && 
  181. print -u2 "Word size: $WordSize; MaxVal: $MaxVal; Byte order: ${ByteOrder[*]}"
  182.  
  183. if [ $# -eq 0 ]; then
  184.     while read line; do
  185.     set -- $line
  186.     PrintChrs "$@"
  187.     done
  188. else
  189.     PrintChrs "$@"
  190. fi
  191.